/*
 * QuadFacilitator.java
 *
 * Created on June 15, 2005, 9:26 AM
 */

package aa.application.AdaptiveQuad;

import java.io.*;

import aa.core.FacilitatorActor;
import aa.core.CyberOrg;
import aa.core.ActorName;
import aa.core.Contract;

import aa.core.CommunicationException;

/**
 *
 * @author  xinghuizhao
 */
public class QuadFacilitator extends FacilitatorActor{
    
    int num; //keep track of the number of computation actors
    
    
    
    long aveRate; //keep track of the average of ticks rate that actors got
    
    long aveRes; //average of total ticks
    
    double aveError; //average error so far; 
    
    long myRate; //ticks rate that will be assigned to new comming actor
    
    long myRes; //ticks that will be assigned to new coming actor
    
    int timesSearch;
    
    Object[] current;
    
    //long myRes; //ticks that will be assigned to new comming actor
    
    /** Creates a new instance of QuadFacilitator */
    public QuadFacilitator(CyberOrg p_cybHost) {
        super(p_cybHost);
        aveRes = 0;
        aveRate = 0;
        aveRes = 0;
        aveError = 0;
        myRate = 0;
        myRes = 0;
        timesSearch =0;
        
    }
    
    public void resourceAlloc(ActorName p_anActor, Double p_doubleError){
        
        double ratio = p_doubleError.doubleValue()/aveError;
        
        if ((aveError==0)||(ratio<0)){
            
            //System.out.println("ratio:"+ratio);
            estimate(p_doubleError.doubleValue());
            
            //m_cybHost.resourceAlloc(p_anActor, myRate);
              
        }else{
            
            estimate(p_doubleError.doubleValue());
            //Contract newContract = new Contract(m_cybHost.getTicks()/2, (long)(myRate*p_doubleError.doubleValue()/aveError),10);
            //for debug
            
            if(ratio<2){
            		m_cybHost.resourceAlloc(p_anActor);
            }
            else{//isolate
                
                //System.out.println("isolate..");
                
                //Contract newContract = new Contract(m_cybHost.getTicks()/2, m_cybHost.getTicksRate()/2,10);
            
                Contract newContract = new Contract(myRes, myRate,10);
                
                //System.out.println(newContract);
                
                ActorName[] actors= new ActorName[1];
                actors[0] = p_anActor;
                
                //System.out.println("start try");
                try {
                    CyberOrg childcyb = m_cybHost.isolate(20, actors, newContract);
                    
                    //System.out.println("isolation done");
                    send(p_anActor,"setFaci",childcyb.getFacilitator());
                    
                    //System.out.println("Height:"+childcyb.getHeight()+"  parent Height: "+m_cybHost.getHeight()+" parent:"+m_cybHost);
                    
                
                }catch (Exception e){
                    System.out.println(e);
                }
            }
        }
    }
    
    public void estimate(double p_dError){
        if (aveError ==0){
            aveRes = m_cybHost.getTicks()/10;
            aveRate = m_cybHost.getTicksRate()/10;
            aveError = p_dError;
            myRate = aveRate;
            myRes = aveRes;
            
            num++;
            
        }else{
            double ratio = p_dError/aveError;
            myRate = (long)(aveRate * ratio);
            myRes = (long)(aveRes * ratio);
            
            aveRate = (aveRate * num + myRate )/(num+1);
            aveRes = (aveRes * num + myRes)/(num+1);
            
            aveError = (aveError * num + p_dError )/(num+1);
            num++;
        }
                
    }
    
    /*
     * This method is called when a remote QuadActor is created.
     */
    
    public void remoteCreateQuad(ActorName p_anClient,Double p_douTolerance,Double a, Double b,String p_strIP){
        String strMeth = "result";
        try{
            ActorName newActor = create("aa.application.AdaptiveQuad.QuadActor_RemoteRes",p_anClient,strMeth,p_douTolerance,p_strIP);
            send(newActor,"setFaci",m_athread.getActorName());
            send(newActor,"quadrature",a,b,newActor,strMeth);
        }catch (Exception e){
            System.err.println("remoteCreation: "+e);
        }
    }
    
    /*
     *find out the remote destination cyberorg to migrate into
     */
    public ActorName findRemoteFaci(String p_strRemoteIP) throws CommunicationException{
        long localprice = m_cybHost.getPrice();
        
        timesSearch++;
        
        
        if (timesSearch %100 ==1){
        
            Object[] destination_price = (Object[])call(new ActorName(p_strRemoteIP,2),"findBestDestination");
            
            current = destination_price;
        }
            
            
            if (((Long)current[1]).longValue()>localprice){
                //System.out.println("localprice: "+localprice +"  remoteP:"+destination_price[1]);
                return null;
            }else{
                
                return ((CyberOrg)current[0]).getFacilitator();
            }
            //return new ActorName("128.233.109.164",2);
        
    }
    
    public Object[] findBestDestination(){
        
        //System.out.println("looking for the best ---findBestDestination");
        CyberOrg cyber = m_cybHost.findBestDestination();
        //CyberOrg cyber = m_cybHost;
        long price = cyber.getPrice();
        Object[] des_pri = new Object[2];
        des_pri[0]=cyber;
        des_pri[1]=new Long(price);
        //System.out.println("looking for the best, over!");
        return des_pri;
    }
    
    public void printCurrentECash(){
        System.out.println("Current ECash: "+m_cybHost.getECash());
    }
    
}
